#define PrynInternal
#define PrynImplementation
#include "platform.h"

typedef struct PrynFileWindows PrynFileWindows;

struct PrynFileWindows
{
	HANDLE handle;
	WIN32_FIND_DATAA info;
};

static PrynResult convert (PrynFileDescription *self)
{
	PrynFileWindows *state = (PrynFileWindows *) self->platform;
	PrynString dot, dotdot;
	uintptr_t offset;

	prynStringLiteral (&dot, ".");
	prynStringLiteral (&dotdot, "..");
	
	while (1)
	{
		prynStringFromZMaximum (&self->filename, state->info.cFileName, MAX_PATH);
		if (!prynStringEqualD (&self->filename, &dot) || !prynStringEqualD (&self->filename, &dotdot))
		{
			if (!FindNextFileA (state->handle, &state->info))
				return PrynResultDone;
		}
		else
			break;
	}
	
	prynStringFree (&self->fullname, self->state);
	
	prynStringNull (&self->extension);
	if (self->filename.length) for (offset = self->filename.length - 1; offset > 0; offset --)
		if (self->filename.pointer [offset] == '/' || self->filename.pointer [offset] == '\\')
			break;
		else if (self->filename.pointer [offset] == '.')
			prynStringSliceToEnd (&self->extension, &self->filename, offset);
	prynStringJoin (&self->fullname, self->state, &self->path, &self->filename);
	
	return PrynResultSuccess;
}

PrynExport (PrynResult, prynFileBeginIteration, (PrynState *state, PrynFileDescription *self, const PrynString *pathBase))
{
	PrynStartFunctionHasState ();
	const char *pathz = 0;
	PrynString path, pathSuffix;
	PrynFileWindows *platform = 0;

	prynClearObject (self);
	prynAssert (state && self && pathBase && pathBase->length, NullArgument);
	prynStringLiteral (&pathSuffix, "\\*.*");
	
	self->state = state;
	self->platform = 0;
	
	path = *pathBase;
	if (path.pointer [path.length - 1] == '/' || path.pointer [path.length - 1] == '\\')
		path.length --;
	
	prynCall (prynStringJoin (&path, state, &path, &pathSuffix));
	pathz = path.pointer;
	path.length -= 3;
	self->path = path;
	
	prynCall (prynAllocateClearedObject (state, &platform));
	
	self->platform = platform;
	platform->handle = FindFirstFileA (pathz, &platform->info);
	prynAssert (platform->handle != INVALID_HANDLE_VALUE, Failure);
	
	result = convert (self);
	
	PrynEndFunctionAfterFailure ({
		if (state)
			prynFree (state, (void *) platform);
		prynFree (state, (void *) pathz);
		prynStringNull (&self->path);
	});
}

PrynExport (PrynResult, prynFileNextIteration, (PrynFileDescription *self))
{
	PrynFileWindows *state;

	if (!self || !self->platform)
		return PrynResultFailure;
	
	state = (PrynFileWindows *) self->platform;
	
	if (!FindNextFileA (state->handle, &state->info))
		return PrynResultDone;
	return convert (self);
}

PrynExport (PrynResult, prynFileEndIteration, (PrynFileDescription *self))
{
	PrynState *state = 0;

	if (!self || !self->state) return PrynResultNullArgument;
	state = self->state;

	prynFree (state, self->platform), self->platform = 0;
	prynStringFree (&self->path, self->state);
	prynStringFree (&self->fullname, self->state);
	prynClearObject (self);
	return PrynResultSuccess;
}

